package com.cfushn.ddd.mp.generator;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * MpGenerator
 *
 * @author CFuShn 2023/3/29 10:04
 */
@SuppressWarnings("unused")
public class MpGenerator {

    private MpGeneratorArgs args;

    public MpGenerator() {
    }

    public MpGenerator(MpGeneratorArgs args) {
        this.args = args;
    }

    public MpGenerator setArgs(MpGeneratorArgs args) {
        this.args = args;
        return this;
    }

    public void generate() {
        System.out.println("\n===================请核对生成配置=====================");
        System.out.println(
            "db_url: " + args.getUrl() + "\nusername: " + args.getUsername() + ",\npassword: "
                + args.getPassword());
        System.out.println("\n目标目录: " + System.getProperty("user.dir")
            + "/" + args.getRelativePathPrefix() + "/src/main/java");
        System.out.println("父包名: " + args.getParentPackageName());
        System.out.printf("实体类包名: " + args.getEntityPackageName());
        System.out.printf("\ndao层包名: " + args.getMapperPackageName());
        System.out.printf("\nservice层包名: " + args.getServicePackageName());
        System.out.printf("\nserviceImpl包名: " + args.getServiceImplPackageName());
        System.out.println("\n");

        // 开始生成
        FastAutoGenerator
            // 1.数据源
            .create(args.getUrl(), args.getUsername(), args.getPassword())

            // 2、全局配置
            .globalConfig(builder ->
                builder.author("mybatis-plus-generator-3.5.x") // 设置作者名
                    .outputDir(System.getProperty("user.dir")
                        + "/" + args.getRelativePathPrefix() + "/src/main/java")   //设置输出路径
                    .commentDate("yyyy-MM-dd hh:mm:ss")   //注释日期
                    .dateType(
                        DateType.ONLY_DATE)   //定义生成的实体类中日期的类型 TIME_PACK=LocalDateTime;ONLY_DATE=Date;
                    .fileOverride()   //覆盖之前的文件
                    .enableSwagger()   //开启 swagger 模式
                    .disableOpenDir()   //禁止打开输出目录，默认打开
            )

            //3、包配置
            .packageConfig(builder ->
                    builder.parent(args.getParentPackageName()) // 设置父包名
                        // .moduleName("xxx")   //设置模块包名
                        .entity(args.getEntityPackageName())   //pojo 实体类包名
                        .mapper(args.getMapperPackageName())   //Mapper 包名
                        .service(args.getServicePackageName()) //Service 包名
                        .serviceImpl(args.getServiceImplPackageName()) // ***ServiceImpl 包名
                // .xml("mapper")  //Mapper XML 包名
                // .controller("controller") //Controller 包名
                // .other("utils") //自定义文件包名
            )

            //4、策略配置
            .strategyConfig((scanner, builder) ->
                builder
                    // 禁用sql过滤, 当enableSqlFilter为true时,正则才会生效
                    .disableSqlFilter()
                    .addInclude(getTables(scanner.apply(
                        "=====================策略配置=======================\n"
                            + "请输入表名(支持正则)，多个用英文逗号分隔 (生成所有表代码请直接输入: all) "))) // 设置需要生成的数据表名
                    // .addTablePrefix("test_", "record_") // 设置过滤表前缀

                    //4.1、Mapper策略配置
                    .mapperBuilder().superClass(BaseMapper.class)   //设置父类
                    .formatMapperFileName("%s" + args.getMapperFileSuffix())   //格式化 mapper 文件名称
                    // .enableMapperAnnotation()       //开启 @Mapper 注解
                    .formatXmlFileName("") // 不生成xml文件
                    // .formatXmlFileName("%sXml") // 格式化 Xml 文件名称

                    //4.2、service 策略配置
                    .serviceBuilder()
                    .formatServiceFileName(
                        "%s"
                            + args.getServiceFileSuffix()) //格式化 service 接口文件名称，%s进行匹配表名，如 UserService
                    .formatServiceImplFileName(
                        "%s"
                            + args.getServiceImplFileSuffix()) //格式化 service 实现类文件名称，%s进行匹配表名，如 UserServiceImpl

                    //4.3、实体类策略配置
                    .entityBuilder().enableLombok() //开启 Lombok
                    .disableSerialVersionUID()  //不实现 Serializable 接口，不生产 SerialVersionUID
                    .logicDeleteColumnName("deleted")   //逻辑删除字段名
                    .naming(NamingStrategy.underline_to_camel)  //数据库表映射到实体的命名策略：下划线转驼峰命
                    .columnNaming(NamingStrategy.underline_to_camel)    //数据库表字段映射到实体的命名策略：下划线转驼峰命
                    .addTableFills(new Column("create_time", FieldFill.INSERT)
                        // new Column("modify_time", FieldFill.INSERT_UPDATE)
                    )   //添加表字段填充，"create_time"字段自动填充为插入时间，"modify_time"字段自动填充为插入修改时间
                    .enableTableFieldAnnotation()       // 开启生成实体时生成字段注解
                    .formatFileName("%s" + args.getEntityFileSuffix()) // 格式化实体类文件名称，%s进行匹配表名，如 User

                    //4.4、Controller策略配置
                    .controllerBuilder()
                    .formatFileName("") // 不生成controller
                    // .formatFileName("%sController") // 格式化 Controller 类文件名称，%s进行匹配表名，如 UserController
                    .enableRestStyle()  //开启生成 @RestController 控制器
            )

            //5、模板引擎
            //默认使用VVelocity模板引擎，可以自定义模板引擎，比如：Freemarker 或 Beetl
            .templateEngine(new VelocityTemplateEngine())

            //6、执行
            .execute();
    }

    // 处理 all 情况
    private static List<String> getTables(String tables) {
        return "all".equals(tables.trim()) ? Collections.emptyList()
            : Arrays.asList(tables.split(","));
    }

}
